package com.itheima.wms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableMap;
import com.itheima.pinda.exception.BizException;
import com.itheima.wms.common.constants.CodeConstant;
import com.itheima.wms.common.enums.OutboundStatus;
import com.itheima.wms.common.enums.PickingStatus;
import com.itheima.wms.common.service.CrudServiceImpl;
import com.itheima.wms.dao.*;
import com.itheima.wms.dto.OutboundDTO;
import com.itheima.wms.entity.*;
import com.itheima.wms.factory.CodeWorker;
import com.itheima.wms.service.IncreaseDecreaseService;
import com.itheima.wms.service.OutboundListService;
import com.itheima.wms.service.OutboundService;
import com.itheima.wms.service.StatusRecordService;
import com.itheima.wms.vo.BatchVO;
import com.itheima.wms.vo.IncreaseDecreaseDetailVO;
import com.itheima.wms.vo.OutboundDetailVO;
import com.itheima.wms.vo.OutboundListSumVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * <p>
 * 业务实现类
 * 出库单
 * </p>
 */
@Slf4j
@Service
public class OutboundServiceImpl extends CrudServiceImpl<OutboundMapper, OutboundEntity> implements OutboundService {

    @Autowired
    private WarehouseMapper warehouseMapper;
    @Autowired
    private AreaMapper areaMapper;
    @Autowired
    private PickingMapper pickingMapper;
    @Autowired
    private HandoverMapper handoverMapper;
    @Autowired
    private OwnerMapper ownerMapper;
    @Autowired
    private CarrierMapper carrierMapper;
    @Autowired
    private OutboundListService outboundListService;
    @Autowired
    private IncreaseDecreaseService increaseDecreaseService;
    @Autowired
    private StatusRecordService statusRecordService;

    @Override
    public boolean save(OutboundEntity entity) {
        boolean result = super.save(entity);
        OutboundEntity dbEntity = this.getById(entity.getId());
        statusRecordService.saveStatus(dbEntity);
        return result;
    }

    @Override
    @Transactional
    public BatchVO picking(List<Long> ids) {
        BatchVO.BatchVOBuilder batchVOBuilder = BatchVO.builder();

        ids.forEach(id -> {
            OutboundEntity outboundEntity = this.getById(id);

            // 校验清单是否有未填写的
            LambdaQueryWrapper<OutboundListEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(OutboundListEntity::getMasterId, id);
            List<OutboundListEntity> outboundListEntities = outboundListService.list(wrapper);
            outboundListEntities = outboundListEntities.stream().filter(item -> (null != item.getOutboundNum() && 0 != item.getOutboundNum())).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(outboundListEntities)) {
                log.info("id:{} 清单未填写完成", id);
                batchVOBuilder.error(outboundEntity.getCode() + "未完成出库清单");
                return;
            }

            if (OutboundStatus.NEW.getCode() != outboundEntity.getStatus()) {
                log.info("id:{} 状态不正确", id);
                batchVOBuilder.error(outboundEntity.getCode() + "状态不合法");
                return;
            }

            LambdaQueryWrapper<PickingEntity> pickingWrapper = new LambdaQueryWrapper<>();
            pickingWrapper.eq(PickingEntity::getMasterId, outboundEntity.getId());
            Integer pickingCount = pickingMapper.selectCount(pickingWrapper);
            if (pickingCount > 0) {
                log.info("id:{} 已存在拣货任务", id);
                batchVOBuilder.error(outboundEntity.getCode() + "已生成过拣货任务");
                return;
            }

            // 修改出库单状态为  拣货中
            outboundEntity.setStatus(OutboundStatus.PICKING.getCode());
            this.updateById(outboundEntity);
            statusRecordService.saveStatus(outboundEntity);

            // 生成拣货任务
            PickingEntity pickingEntity = new PickingEntity();
            BeanUtils.copyProperties(outboundEntity, pickingEntity);
            pickingEntity.setMasterId(outboundEntity.getId());
            pickingEntity.setCode(CodeWorker.nextCode(CodeConstant.PICKING));
            pickingEntity.setWaveCode(pickingEntity.getCode().replace(CodeConstant.PICKING, CodeConstant.WAVE)); // 波次任务随拣货任务变更
            pickingEntity.setOutboundCode(outboundEntity.getCode());
            pickingEntity.setPickingNum(outboundEntity.getGoodsNum());
            pickingEntity.setStatus(PickingStatus.NEW.getCode());  //初始状态
            pickingEntity.setId(null);
            pickingMapper.insert(pickingEntity);
            statusRecordService.saveStatus(pickingEntity);

            batchVOBuilder.result(pickingEntity.getCode());
        });

        return batchVOBuilder.build();
    }

    @Override
    public IPage<OutboundDetailVO> pageDetail(Page<OutboundDetailVO> page, Map data) {
        IPage<OutboundDetailVO> iPage = this.baseMapper.selectOutboundDetail(page, data);
        return iPage;
    }

    @Override
    public OutboundDetailVO getDetail(Long id) {
        OutboundDetailVO outboundDetailVO = new OutboundDetailVO();
        OutboundEntity outboundEntity = this.getById(id);
        BeanUtils.copyProperties(outboundEntity, outboundDetailVO);

        LambdaQueryWrapper<PickingEntity> pickingWrapper = new LambdaQueryWrapper<>();
        pickingWrapper.eq(PickingEntity::getMasterId, id);
        PickingEntity pickingEntity = pickingMapper.selectOne(pickingWrapper);
        outboundDetailVO.setPickingEntity(pickingEntity);

        LambdaQueryWrapper<HandoverEntity> handoverWrapper = new LambdaQueryWrapper<>();
        handoverWrapper.eq(HandoverEntity::getMasterId, id);
        HandoverEntity handoverEntity = handoverMapper.selectOne(handoverWrapper);
        outboundDetailVO.setHandoverEntity(handoverEntity);

        // 构建状态时间
        List<String> timeArray = statusRecordService.listTime(outboundEntity.getId());
        outboundDetailVO.setTimeArray(timeArray);

        // 仓库名称
        WarehouseEntity warehouseEntity = warehouseMapper.selectById(outboundEntity.getWarehouseId());
        outboundDetailVO.setWarehouseName(warehouseEntity == null ? String.valueOf(outboundEntity.getWarehouseId()) : warehouseEntity.getName());
        // 库区名称
        AreaEntity areaEntity = areaMapper.selectById(outboundEntity.getAreaId());
        outboundDetailVO.setAreaName(areaEntity == null ? String.valueOf(outboundEntity.getAreaId()) : areaEntity.getName());

        // 货主
        outboundDetailVO.setOwner(ownerMapper.selectById(outboundEntity.getOwnerId()));
        outboundDetailVO.setOwnerName(outboundDetailVO.getOwner().getName());
        outboundDetailVO.setOwnerCode(outboundDetailVO.getOwner().getCode());

        // 承运商
        outboundDetailVO.setCarrierName(carrierMapper.selectById(outboundEntity.getCarrierId()).getName());

        // 货品信息详情
        OutboundListSumVO outboundListSumVO = outboundListService.sumOutboundListDetail(ImmutableMap.of("masterId", outboundDetailVO.getId()));
        outboundDetailVO.setGoodsTotal(outboundListSumVO.getGoodsTotal());
        outboundDetailVO.setVolumeTotal(outboundListSumVO.getVolumeTotal());

        // 损益
        if (null != pickingEntity) {
            List<IncreaseDecreaseDetailVO> increaseDecreaseEntities = increaseDecreaseService.listDetail(ImmutableMap.of("taksId", pickingEntity.getId()));
            if (!CollectionUtils.isEmpty(increaseDecreaseEntities)) {
                outboundDetailVO.setIdMoney(increaseDecreaseEntities.stream().filter(item -> item.getIdMoney() != null).map(IncreaseDecreaseEntity::getIdMoney).reduce(BigDecimal.ZERO, BigDecimal::add));
                outboundDetailVO.setIdList(increaseDecreaseEntities);
            }
        }
        return outboundDetailVO;
    }

    @Override
    @Transactional
    public void cancel(OutboundDTO data) {
        OutboundEntity outboundEntity = this.getById(data.getId());
        if (null == outboundEntity) {
            throw new BizException("出库单未找到");
        }
        if (outboundEntity.getStatus() != OutboundStatus.NEW.getCode()) {
            throw new BizException("只能取消新建的出库单");
        }
        outboundEntity.setStatus(OutboundStatus.CANCEL.getCode());
        this.updateById(outboundEntity);
        statusRecordService.saveStatus(outboundEntity);

        LambdaQueryWrapper<OutboundListEntity> outboundListWrapper = new LambdaQueryWrapper<>();
        outboundListWrapper.eq(OutboundListEntity::getMasterId, outboundEntity.getId());
        List<OutboundListEntity> outboundListEntities = outboundListService.list(outboundListWrapper);
        log.info("取消出库单明细：{}", outboundListEntities);
        outboundListService.cancelBatch(outboundListEntities);
    }
}

